package com.googlecode.mapperdao

import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.{Matchers, FunSuite}
import org.joda.time.DateTime
import com.googlecode.mapperdao.jdbc.Setup

/**
 * @author kostantinos.kougios
 *
 *         25 Jul 2012
 */
@RunWith(classOf[JUnitRunner])
class MultipleInheritance1TableSuite extends FunSuite with Matchers
{

	if (Setup.database == "h2") {
		implicit val (jdbc, mapperDao, queryDao) = Setup.setupMapperDao(List(ReminderEntity))

		test("crud for Daily") {
			createTables()

			val inserted = mapperDao.insert(ReminderEntity, Daily(12))
			inserted should be === Daily(12)
			mapperDao.select(ReminderEntity, inserted.id).get should be === Daily(12)

			val updated = mapperDao.update(ReminderEntity, inserted, Daily(14))
			updated should be === Daily(14)
			mapperDao.select(ReminderEntity, inserted.id).get should be === Daily(14)

			mapperDao.delete(ReminderEntity, updated)
			mapperDao.select(ReminderEntity, inserted.id) should be === None
		}

		test("crud for Weekly") {
			createTables()

			val inserted = mapperDao.insert(ReminderEntity, Weekly(1, 12))
			inserted should be === Weekly(1, 12)
			mapperDao.select(ReminderEntity, inserted.id).get should be === Weekly(1, 12)

			val updated = mapperDao.update(ReminderEntity, inserted, Weekly(2, 14))
			updated should be === Weekly(2, 14)
			mapperDao.select(ReminderEntity, inserted.id).get should be === Weekly(2, 14)

			mapperDao.delete(ReminderEntity, updated)
			mapperDao.select(ReminderEntity, inserted.id) should be === None
		}

		test("query") {
			createTables()

			val w1 = mapperDao.insert(ReminderEntity, Weekly(1, 12))
			val w2 = mapperDao.insert(ReminderEntity, Weekly(1, 13))
			val d1 = mapperDao.insert(ReminderEntity, Daily(12))
			val d2 = mapperDao.insert(ReminderEntity, Daily(12))

			import Query._
			// alias
			val re = ReminderEntity

			(select
				from re
				where re.hourOfDay === 1.toShort).toSet should be === Set(w1, w2)

			(select
				from re
				where re.hourOfDay === 12.toShort).toSet should be === Set(d1, d2)
		}

		def createTables() {
			Setup.dropAllTables(jdbc)
			Setup.queries(this, jdbc).update("ddl")
		}
	}

	abstract class Reminder

	case class Daily(hourOfDay: Short) extends Reminder

	case class Weekly(hourOfDay: Short, dayOfWeek: Short) extends Reminder

	case class RemindOnce(time: DateTime) extends Reminder

	object ReminderEntity extends Entity[Int, SurrogateIntId, Reminder]
	{
		val id = key("id") autogenerated (_.id)
		// we will map the inheritance into the "type" column 
		val t = column("type") to {
			case _: Daily => 0 // type=0 for Daily class
			case _: Weekly => 1 // type=1 for Weekly class
			case _: RemindOnce => 2 // type=2 for Monthly class
		}
		val hourOfDay = column("hourOfDay") to {
			case daily: Daily => daily.hourOfDay
			case weekly: Weekly => weekly.hourOfDay
			case _: RemindOnce => -1.toShort
		}
		val dayOfWeek = column("dayOfWeek") to {
			case _: Daily => -1.toShort
			case weekly: Weekly => weekly.dayOfWeek
			case _: RemindOnce => -1.toShort
		}
		val time = column("time") to {
			case _: Daily => null
			case _: Weekly => null
			case remindOnce: RemindOnce => remindOnce.time
		}

		def constructor(implicit m: ValuesMap) = m(t) match {
			case 0 => new Daily(hourOfDay) with Stored
			{
				val id: Int = ReminderEntity.id
			}
			case 1 =>
				new Weekly(hourOfDay, dayOfWeek) with Stored
				{
					val id: Int = ReminderEntity.id
				}
			case 2 => new RemindOnce(time) with Stored
			{
				val id: Int = ReminderEntity.id
			}
		}
	}

}